use std::{env, io::Result};

use actix_cors::Cors;
// use actix_session::{storage::CookieSessionStore, SessionMiddleware};
use actix_web::{main, web, App, HttpServer};
use api::contracts::{create_contract, delete_contract, page_contract, update_contract};
use api::imports::import_project_from_file;
use api::invoice::{create_invoice, delete_invoice, page_invoice, update_invoice};
use api::materials::{
    create_material, delete_material, import_material, page_materials, update_material,
    verify_amount,
};
use api::payments::{create_payment, delete_payment, page_payment, update_payment};
use api::projects::{
    contract_preview, create_project, delete_project, overview_project, page_project,
    update_project,
};
use api::providers::{
    create_provider, delete_provider, overview_provider, page_provider, update_provider,
};
use api::users::{
    create_user, delete_user, login, logout, page_user, update_password, update_user,
};
use diesel::r2d2::{self, ConnectionManager, Pool};
use diesel::MysqlConnection;
mod api;
mod db;
mod schema;

type DbPool = Pool<ConnectionManager<MysqlConnection>>;

#[main]
async fn main() -> Result<()> {
    dotenvy::dotenv().ok();
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
    let db_pool = init_db_pool();

    HttpServer::new(move || {
        let cors = Cors::default()
            .allow_any_header()
            .allow_any_origin()
            .allow_any_method()
            .supports_credentials()
            .max_age(3600);
        App::new()
            .app_data(web::Data::new(db_pool.clone()))
            // .wrap(
            //     SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&[0; 64]))
            //         .cookie_secure(true)
            //         .build(),
            // )
            .wrap(cors)
            .service(
                web::scope("/api/users")
                    .service(login)
                    .service(logout)
                    .service(update_password)
                    .service(page_user)
                    .service(update_user)
                    .service(create_user)
                    .service(delete_user),
            )
            .service(
                web::scope("/api/material")
                    .service(page_materials)
                    .service(create_material)
                    .service(update_material)
                    .service(delete_material)
                    .service(verify_amount)
                    .service(import_material),
            )
            .service(
                web::scope("api/project")
                    .service(page_project)
                    .service(create_project)
                    .service(update_project)
                    .service(delete_project)
                    .service(import_project_from_file),
            )
            .service(
                web::scope("/api/provider")
                    .service(create_provider)
                    .service(page_provider)
                    .service(update_provider)
                    .service(delete_provider),
            )
            .service(
                web::scope("/api/contract")
                    .service(page_contract)
                    .service(create_contract)
                    .service(update_contract)
                    .service(delete_contract),
            )
            .service(
                web::scope("/api/payment")
                    .service(page_payment)
                    .service(create_payment)
                    .service(update_payment)
                    .service(delete_payment),
            )
            .service(
                web::scope("/api/invoice")
                    .service(page_invoice)
                    .service(create_invoice)
                    .service(update_invoice)
                    .service(delete_invoice),
            )
            .service(
                web::scope("/api/overview")
                    .service(overview_project)
                    .service(overview_provider)
                    .service(contract_preview),
            )
    })
    .bind(("0.0.0.0", 8080))?
    .run()
    .await
}

fn init_db_pool() -> DbPool {
    let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let manager = r2d2::ConnectionManager::<MysqlConnection>::new(db_url);
    r2d2::Pool::builder()
        .build(manager)
        .expect("database URL should be valid path to Mysql url")
}
